#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <netinet/tcp.h>
#include "http_parser.h"
#include <iostream>

#define PORT_NO  40001
#define MAX_BACK_LOG   10
#define DEFAULT_BUFFER_SIZE 512

//计数器，检测header_field_cb和header_value_cb是否是成對调用
static int count = 0;

//other callback
int data_cb(http_parser *p, const char *at, std::size_t length) {
    std::cout << "data_cb called " << std::endl;
    return 0;
}

//header field callback
int header_field_cb(http_parser *p, const char *at, std::size_t length) {
    std::string str(at, length);
    std::cout << "header_field_cb cb-> :" << str << "index = " << ++count << std::endl;
    return 0;
}

//header value callback
int header_value_cb(http_parser *p, const char *at, std::size_t length) {
    std::string str(at, length);
    std::cout << "header_value_cb value cb-> " << str << "index = " << ++count << std::endl;
    return 0;
}

//main func
int main() {
    ///定义sockfd
    int server_sockfd = socket(AF_INET, SOCK_STREAM, 0);

    ///定义sockaddr_in
    struct sockaddr_in server_sockaddr;
    server_sockaddr.sin_family = AF_INET;
    server_sockaddr.sin_port = htons(PORT_NO);
    server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);

    //set socket SO_REUSEADDR,避免因给Ctrl+C中断程序之后，返回端口被占用的问题
    int on = 1;
    if ((setsockopt(server_sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) < 0) {
        perror("setsockopt failed");
        exit(EXIT_FAILURE);
    }
    //bind
    if (bind(server_sockfd, (struct sockaddr *) &server_sockaddr, sizeof(server_sockaddr)) == -1) {
        perror("bind");
        exit(1);
    }
    //listen
    if (listen(server_sockfd, MAX_BACK_LOG) == -1) {
        perror("listen");
        exit(1);
    }
    //buffers 用来读取的buffer
    char buffer[DEFAULT_BUFFER_SIZE];
    //client info 客户端相关信息
    struct sockaddr_in client_addr;
    socklen_t length = sizeof(client_addr);
    //accept，demo只接受一个链接用作测试
    int conn = accept(server_sockfd, (struct sockaddr *) &client_addr, &length);
    //set socket TCP_NODELAY
    int enable = 1;
    setsockopt(conn, IPPROTO_TCP, TCP_NODELAY, (void *) &enable, sizeof(enable));
    if (conn < 0) {
        perror("connect");
        exit(1);
    }

    //init settings
    http_parser_settings settings;
    http_parser_settings_init(&settings);
    //add callbacks
    settings.on_header_value = header_value_cb;
    settings.on_url = data_cb;
    settings.on_header_field = header_field_cb;
    //init parser,每个连接使用一个，Demo程序有且仅有一个链接，所以只需要一个
    struct http_parser parser;
    http_parser_init(&parser, HTTP_REQUEST);
    //read loop
    while (1) {
        memset(buffer, 0, sizeof(buffer));
        ssize_t len = recv(conn, buffer, sizeof(buffer), 0);
        if (strcmp(buffer, "exit\n") == 0)
            break;
        //write to stdout , eg. console
        fputs(buffer, stdout);
        //解析的数据量，和socekt读取的数据量相等,如果不等，说明协议报文有问题
        std::size_t nparsed = http_parser_execute(&parser, &settings, buffer, len);  //decode buf
        if (nparsed != len) {
            //error
            goto shutdown_con;
        }
    }

    shutdown_con:
    close(conn);
    close(server_sockfd);
    //exit result
    return EXIT_SUCCESS;
}
